/*
 * 文件名： CiticExpaySignUtil.java
 * 
 * 工程名称: bis-bank-citic
 *
 * Gopay
 *
 * 创建日期： 2016年6月22日
 *
 * Copyright(C) 2016, by www.gopay.com.cn Inc.All rights reserved.
 *
 * 原始作者: 宣广海
 *
 */
package com.gopay.bis.citic.expay.operation;

import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.cert.X509Certificate;
import java.text.SimpleDateFormat;
import java.util.Date;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.lsy.baselib.crypto.algorithm.DESede;
import com.lsy.baselib.crypto.algorithm.RSA;
import com.lsy.baselib.crypto.protocol.PKCS7Signature;
import com.lsy.baselib.crypto.util.Base64;
import com.lsy.baselib.crypto.util.CryptUtil;
import com.lsy.baselib.crypto.util.FileUtil;

/**
 * 中信银行快捷支付报文签名操作工具类
 *
 * @author 宣广海
 *
 * @version
 *
 * @since 2016年6月22日
 */
public class CiticExpaySignUtil {
	/**
	 * 日志对象
	 */
	private static Logger logger = LoggerFactory.getLogger(CiticExpaySignUtil.class);

	public static byte[] LinkByteArrays(byte[] arr1, byte[] arr2) {
		int n1 = arr1.length;
		int n2 = arr2.length;
		byte[] newArr = new byte[n1 + n2];
		System.arraycopy(arr1, 0, newArr, 0, n1);
		System.arraycopy(arr2, 0, newArr, n1, n2);
		return newArr;
	}

	public static byte[] LinkByteArrays(byte[] arr1, byte[] arr2, byte[] arr3) {
		int n1 = arr1.length;
		int n2 = arr2.length;
		int n3 = arr3.length;
		byte[] newArr = new byte[n1 + n2 + n3];
		System.arraycopy(arr1, 0, newArr, 0, n1);
		System.arraycopy(arr2, 0, newArr, n1, n2);
		System.arraycopy(arr3, 0, newArr, n1 + n2, n3);
		return newArr;
	}

	public static byte[] LinkByteArrays(byte[] arr1, byte[] arr2, byte[] arr3, byte[] arr4) {
		int n1 = arr1.length;
		int n2 = arr2.length;
		int n3 = arr3.length;
		int n4 = arr4.length;
		byte[] newArr = new byte[n1 + n2 + n3 + n4];
		System.arraycopy(arr1, 0, newArr, 0, n1);
		System.arraycopy(arr2, 0, newArr, n1, n2);
		System.arraycopy(arr3, 0, newArr, n1 + n2, n3);
		System.arraycopy(arr4, 0, newArr, n1 + n2 + n3, n4);
		return newArr;
	}

	/**
	 * 
	 * 功能描述： 1）假设请求或响应报文（如XML格式的报文）明文为X 2）使用发送方的私钥对X进行签名，得到BASE64编码的S
	 * 3）产生一个随机数R作为会话密钥，对拼接数据“<signature>签名S</signature>+明文报文X”
	 * 使用3DES算法(CBC模式)加密，得到数据的密文（2进制）M 4）使用接收方的公钥对R进行RSA加密，得到BASE64编码的K
	 * 5）拼接待发送报文体为：<sessionkey>会话密钥密文K</sessionkey>M
	 *
	 * @param plainMessage
	 *            明文报文
	 * @param privateFilePwd
	 *            发送方私钥文件密码
	 * @param privateFileName
	 *            发送方私钥文件名
	 * @param sendPublicCer
	 *            发送方cer证书文件名
	 * @param acceptPublicCer
	 *            接收方cer证书文件名
	 * @return
	 * 
	 * @author 宣广海
	 * @throws Exception
	 *
	 * @since 2016年6月22日
	 *
	 * @update:[变更日期YYYY-MM-DD][更改人姓名][变更描述]
	 */
	public static byte[] sign_crypt(String plainMessage, String privateFilePwd, String privateFileName,
			String sendPublicCer, String acceptPublicCer) throws Exception {
		try {
//			logger.error("plainMessage=" + plainMessage + ", privateFilePwd=" + privateFilePwd + ", privateFileName="
//					+ privateFileName + ", sendPublicCer=" + sendPublicCer + ", acceptPublicCer=" + acceptPublicCer);
			/**
			 * 私钥密码
			 */
			char[] keyPassword = new String(privateFilePwd).toCharArray();
			/**
			 * 
			 */
			byte[] base64EncodedPrivatekey = FileUtil.read4file(privateFileName);
			PrivateKey signerPrivatekey = CryptUtil.decryptPrivateKey(Base64.decode(base64EncodedPrivatekey),
					keyPassword);
			byte[] base64EncodedCert = FileUtil.read4file(sendPublicCer);
			X509Certificate signerCertificate = CryptUtil.generateX509Certificate(Base64.decode(base64EncodedCert));
			/**
			 * 签名中不附带原文
			 */
			byte[] signature = PKCS7Signature.sign(plainMessage.getBytes(), signerPrivatekey, signerCertificate, null,
					false);
			String b64StrSignature = new String(Base64.encode(signature));
			/**
			 * 带签名的报文
			 */
			byte[] signedMsg = LinkByteArrays(("<signature>" + b64StrSignature + "</signature>").getBytes(),
					plainMessage.getBytes());
			//logger.error("signedMsg=" + new String(signedMsg));
			/**
			 * 产生随机会话密钥明文
			 */
			byte[] sessionKey = DESede.createKey(DESede.DESEDE_KEY_112_BIT);
			byte[] iv = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
			/**
			 * 签名报文再加密
			 */
			byte[] cryptMsg = DESede.encrypt(signedMsg, sessionKey, iv);

			byte[] base64EncodedCert2 = FileUtil.read4file(acceptPublicCer);
			X509Certificate cert2 = CryptUtil.generateX509Certificate(Base64.decode(base64EncodedCert2));
			PublicKey pubKey2 = cert2.getPublicKey();
			/**
			 * 随机会话密钥密文
			 */
			byte[] sessionKeyCipher = RSA.encrypt(sessionKey, pubKey2.getEncoded());
			/**
			 * 完整报文体
			 */
			byte[] msgBody = LinkByteArrays("<sessionkey>".getBytes(), Base64.encode(sessionKeyCipher),
					"</sessionkey>".getBytes(), cryptMsg);
			/**
			 * 报文头,后续信息长度+标识位(P=明文，E=密文)和保留域
			 */
			byte[] msgHead = String.format("%06dE123456789", 10 + msgBody.length).getBytes();
			
			/**
			 * 返回完整报文
			 */
			return LinkByteArrays(msgHead, msgBody);
		} catch (Exception e) {
			logger.error("出错了：" + e);
			throw new Exception();
		}
	}
}
